package com.designpatterns.ReadersWriter;

/**
 * Created by 41579 on 2017/6/9.
 */
public class ReadWriteLock {
    private int readingReaders;
    private int writtingWriters;
    private int waittingWriters;
    private boolean writeFirst = true;
    private ReadLock readLock;
    private WriteLock writeLock;

    public int getReadingReaders() {
        return readingReaders;
    }

    public void setReadingReaders(int readingReaders) {
        this.readingReaders = readingReaders;
    }

    public int getWrittingWriters() {
        return writtingWriters;
    }

    public void setWrittingWriters(int writtingWriters) {
        this.writtingWriters = writtingWriters;
    }

    public int getWaittingWriters() {
        return waittingWriters;
    }

    public void setWaittingWriters(int waittingWriters) {
        this.waittingWriters = waittingWriters;
    }

    public ReadWriteLock() {
        this.readLock = new ReadLock();
        this.writeLock = new WriteLock();
    }

    public ReadLock getReadLock() {
        return readLock;
    }

    public void setReadLock(ReadLock readLock) {
        this.readLock = readLock;
    }

    public WriteLock getWriteLock() {
        return writeLock;
    }

    public void setWriteLock(WriteLock writeLock) {
        this.writeLock = writeLock;
    }

    public class ReadLock {
        public void lock() throws InterruptedException {
            synchronized (ReadWriteLock.this) {
                while (writtingWriters > 0 || (writeFirst && waittingWriters > 0)) {
                    ReadWriteLock.this.wait();
                }
                readingReaders++;
            }
        }

        public void unlock() throws InterruptedException {
            synchronized (ReadWriteLock.this) {
                readingReaders--;
                writeFirst = true;
                ReadWriteLock.this.notifyAll();
            }
        }
    }

    public class WriteLock {
        public void lock() throws InterruptedException {
            synchronized (ReadWriteLock.this) {
                waittingWriters++;
                while (readingReaders > 0 || writtingWriters > 0) {
                    ReadWriteLock.this.wait();
                }
                waittingWriters--;
                writtingWriters++;
            }
        }

        public void unlock() throws InterruptedException {
            synchronized (ReadWriteLock.this) {
                writtingWriters--;
                writeFirst = false;
                ReadWriteLock.this.notifyAll();
            }
        }
    }
}

